﻿#include <QCoreApplication>
#include <QThread>
#include <QDateTime>
#include "JZCo.h"

void jzco_init()
{
    g_scheduler->init();
}

void jzco_yield()
{
    auto co = g_scheduler->currentCoroutine();
    g_scheduler->yield(co);
}

void jzco_sleep(int ms)
{
    JZCoCoroutine* task = g_scheduler->currentCoroutine();
    Q_ASSERT(task);

    QTimer t;
    
    qint64 cur_time = QDateTime::currentMSecsSinceEpoch();
    t.connect(&t,&QTimer::timeout,[task,cur_time,ms]
    {
        qint64 now_time = QDateTime::currentMSecsSinceEpoch();
        if (now_time - cur_time < ms)
        {
            if (task->isInterrupt())
                g_scheduler->resume(task);
        }
        else
        {
            g_scheduler->resume(task);
        }
    });

    int check_gap = qMax(10, ms / 10);
    check_gap = qMin(50, check_gap);
    t.start(check_gap);
    g_scheduler->yield(task);
    t.stop();
    
    if(task->isInterrupt())
        throw JZCoInterrupt();
}

void jzco_sleep_uninterrupt(int ms)
{
    JZCoCoroutine* task = g_scheduler->currentCoroutine();

    QTimer t;
    t.setSingleShot(true);
    t.connect(&t, &QTimer::timeout, [task]
    {
        g_scheduler->resume(task);
    });
    t.start(ms);

    g_scheduler->yield(task);
    t.stop();
}

void jzco_waitThread(std::function<void()> func)
{
    JZCoThread t(func);
    t.start();
    while (true)
    {
        if (t.isRunning())
            jzco_sleep_uninterrupt(10);
        else
            break;
    }

    JZCoCoroutine* task = g_scheduler->currentCoroutine();
    if (task->isInterrupt())
        throw JZCoInterrupt();
}

void jzco_waitCoroutine(const QList<JZCoCoroutinePtr>& co_list)
{
    while (true)
    {
        bool all_finish = true;
        for (int i = 0; i < co_list.size(); i++)
        {
            if (!co_list[i]->isFinish())
            {
                all_finish = false;
                break;
            }
        }
        if (all_finish)
            return;

        if(g_scheduler->isInCoroutine())
            jzco_sleep(20);
        else
        {
            qApp->processEvents();
            QThread::msleep(20);
        }
    }
}

void jzco_spawn(JZCoCoroutinePtr co_ptr)
{
    g_scheduler->startTask(co_ptr);
}

JZCoCoroutinePtr jzco_spawn(const std::function<void()> &func)
{
    JZCoCoroutinePtr ptr =  JZCoCoroutinePtr(new JZCoCoroutine());
    ptr->setTask(func);
    g_scheduler->startTask(ptr);
    return ptr;
}
